/* $Id: //depot/blt/lib/libposix/exec.c#1 $
**
** Copyright 1999 Sidney Cammeresi
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
** 1. Redistributions of source code must retain the above copyright
**    notice, this list of conditions, and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
**    notice, this list of conditions, and the following disclaimer in the
**    documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
**    derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <elf.h>
#include <sys/stat.h>
#include <blt/syscall.h>
#include <blt/libsyms.h>

weak_alias (_execve, execve)

int _execve (const char *path, char * const *argv, char * const *envp)
{
	char *ptr, *c;
	char **n_argv;
	int i, j, fd, area, sarea, res, size, total;
	unsigned int *magic;
	struct stat buf;
	uint32 *stack, *top;
	
	res = _stat (path, &buf);
	if (res)
	{
		errno = ENOENT;
		return -1;
	}
	size = (buf.st_size & 0xfff) ? (buf.st_size & 0xfffff000) + 0x1000 :
		buf.st_size;
	fd = _open (path, O_RDONLY, 0);
	if (fd < 0)
	{
		errno = ENOENT;
		return -1;
	}
	area = area_create (size, 0, (void **) &ptr, 0);
	res = _read (fd, ptr, size);
	magic = (unsigned int *) ptr;
	if (*magic != ELF_MAGIC)
	{
		errno = ENOEXEC;
		area_destroy (area);
		return -1;
	}
	// _close(fd);

	/* compute how much stack we need for arguments */
	for (i = total = 0; argv[i] != NULL; i++)
		total += strlen (argv[i]) + 1;
	total = (total & ~3) ? (total & ~3) + 4 : total;

	/* create stack */
	sarea = area_create (0x1000, 0, (void **) &stack, 0);

	/* copy arguments and set up the argv array */
	c = (char *) stack + 0xffc - total;
	n_argv = (char **) (c - i * sizeof (char *));
	for (j = 0; j < i; j++)
	{
		strcpy (c, argv[j]);
		n_argv[j] = (char *) (0x3ff000 + ((unsigned int) c & 0xfff));
		c += strlen (argv[j]) + 1;
	}

	/* drop argc and argv on the top */
	top = (uint32 *) ((unsigned int) stack + 0x1000 - (total + (i + 3) *
		sizeof (char *)));
	top[0] = i;
	top[1] = 0x3ff000 + (((uint32) top + 8) & 0xfff);

	/* off we go */
	res = thr_spawn (0x1074, 0x3ff000 + ((unsigned int) top & 0xfff) + 0x10,
		area, 0x1000, sarea, 0x3ff000, argv[0]);

	/* clean up */
	area_destroy (area);
	area_destroy (sarea);
	return res;
}

